using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Matrix.ServiceCommunication.Options;
using Matrix.ServiceCommunication.Services;
using Matrix.ServiceCommunication.Contracts.Dtos;

namespace Matrix.ServiceCommunication.Discovery
{
    /// <summary>
    /// Matrix服务发现提供者
    /// 集成Matrix.ServiceDiscovery管理系统
    /// </summary>
    public class MatrixServiceDiscoveryProvider : IServiceDiscoveryProvider
    {
        private readonly HttpClient _httpClient;
        private readonly IOptionsMonitor<ServiceCommunicationOptions> _options;
        private readonly ILogger<MatrixServiceDiscoveryProvider> _logger;
        private readonly IMemoryCache _cache;

        public MatrixServiceDiscoveryProvider(
            HttpClient httpClient,
            IOptionsMonitor<ServiceCommunicationOptions> options,
            ILogger<MatrixServiceDiscoveryProvider> logger,
            IMemoryCache cache)
        {
            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
            _options = options ?? throw new ArgumentNullException(nameof(options));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            _cache = cache ?? throw new ArgumentNullException(nameof(cache));
        }

        /// <summary>
        /// 获取服务地址
        /// </summary>
        public async Task<Uri> GetServiceAddressAsync(string serviceName, CancellationToken cancellationToken = default)
        {
            var cacheKey = $"service_address:{serviceName}";

            // 优先从缓存获取
            if (_cache.TryGetValue(cacheKey, out Uri? cachedAddress) && cachedAddress != null)
            {
                _logger.LogDebug("从缓存获取服务地址: {ServiceName} -> {Address}", serviceName, cachedAddress);
                return cachedAddress;
            }

            // 从服务发现管理系统中获取
            var healthyInstances = await GetHealthyInstancesAsync(serviceName, cancellationToken);

            if (!healthyInstances.Any())
            {
                throw new InvalidOperationException($"服务 {serviceName} 没有可用的健康实例");
            }

            // 负载均衡选择实例
            var selectedInstance = SelectInstanceByLoadBalancing(serviceName, healthyInstances);
            var address = new Uri(selectedInstance.Address);

            // 缓存结果
            var cacheOptions = new MemoryCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(_options.CurrentValue.ServiceDiscovery.CacheSeconds)
            };
            _cache.Set(cacheKey, address, cacheOptions);

            _logger.LogInformation("获取服务地址: {ServiceName} -> {Address} (实例: {InstanceId})",
                serviceName, address, selectedInstance.InstanceId);

            return address;
        }

        /// <summary>
        /// 获取所有健康实例
        /// </summary>
        public async Task<List<ServiceInstanceDto>> GetHealthyInstancesAsync(string serviceName, CancellationToken cancellationToken = default)
        {
            var options = _options.CurrentValue;
            var serviceDiscoveryUrl = $"{options.ServiceDiscovery.BaseUrl}/api/service-discovery/healthy-instances/{serviceName}";

            try
            {
                var response = await _httpClient.GetAsync(serviceDiscoveryUrl, cancellationToken);
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync(cancellationToken);
                var instances = JsonSerializer.Deserialize<List<ServiceInstanceDto>>(json, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                });

                _logger.LogDebug("获取健康实例: {ServiceName} -> {Count}个实例", serviceName, instances?.Count ?? 0);

                return instances ?? new List<ServiceInstanceDto>();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取健康实例失败: {ServiceName}", serviceName);
                throw new InvalidOperationException($"无法从服务发现系统获取 {serviceName} 的健康实例", ex);
            }
        }

        /// <summary>
        /// 注册服务实例
        /// </summary>
        public async Task RegisterServiceAsync(RegisterServiceDto serviceDto, CancellationToken cancellationToken = default)
        {
            var options = _options.CurrentValue;
            var registerUrl = $"{options.ServiceDiscovery.BaseUrl}/api/service-discovery/register-service";

            try
            {
                var json = JsonSerializer.Serialize(serviceDto);
                var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

                var response = await _httpClient.PostAsync(registerUrl, content, cancellationToken);
                response.EnsureSuccessStatusCode();

                _logger.LogInformation("服务注册成功: {ServiceName}/{InstanceId}",
                    serviceDto.ServiceName, serviceDto.InstanceId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "服务注册失败: {ServiceName}/{InstanceId}",
                    serviceDto.ServiceName, serviceDto.InstanceId);
                throw new InvalidOperationException($"服务注册失败: {serviceDto.ServiceName}", ex);
            }
        }

        /// <summary>
        /// 注销服务实例
        /// </summary>
        public async Task UnregisterServiceAsync(string serviceName, string instanceId, CancellationToken cancellationToken = default)
        {
            var options = _options.CurrentValue;
            var unregisterUrl = $"{options.ServiceDiscovery.BaseUrl}/api/service-discovery/unregister-service-instance?serviceName={serviceName}&instanceId={instanceId}";

            try
            {
                var response = await _httpClient.PostAsync(unregisterUrl, null, cancellationToken);
                response.EnsureSuccessStatusCode();

                _logger.LogInformation("服务注销成功: {ServiceName}/{InstanceId}", serviceName, instanceId);

                // 清除相关缓存
                var cacheKey = $"service_address:{serviceName}";
                _cache.Remove(cacheKey);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "服务注销失败: {ServiceName}/{InstanceId}", serviceName, instanceId);
                throw new InvalidOperationException($"服务注销失败: {serviceName}/{instanceId}", ex);
            }
        }

        /// <summary>
        /// 发送心跳
        /// </summary>
        public async Task SendHeartbeatAsync(HeartbeatDto heartbeatDto, CancellationToken cancellationToken = default)
        {
            var options = _options.CurrentValue;
            var heartbeatUrl = $"{options.ServiceDiscovery.BaseUrl}/api/service-discovery/heartbeat";

            try
            {
                var json = JsonSerializer.Serialize(heartbeatDto);
                var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

                var response = await _httpClient.PostAsync(heartbeatUrl, content, cancellationToken);

                // 心跳失败不应该抛出异常，只记录日志
                if (!response.IsSuccessStatusCode)
                {
                    _logger.LogWarning("心跳发送失败: {ServiceName}/{InstanceId}, 状态码: {StatusCode}",
                        heartbeatDto.ServiceName, heartbeatDto.InstanceId, response.StatusCode);
                }
                else
                {
                    _logger.LogDebug("心跳发送成功: {ServiceName}/{InstanceId}",
                        heartbeatDto.ServiceName, heartbeatDto.InstanceId);
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "心跳发送异常: {ServiceName}/{InstanceId}",
                    heartbeatDto.ServiceName, heartbeatDto.InstanceId);
                // 心跳异常不应该抛出，避免影响主业务
            }
        }

        /// <summary>
        /// 更新实例健康状态
        /// </summary>
        public async Task UpdateInstanceHealthAsync(UpdateInstanceHealthDto healthDto, CancellationToken cancellationToken = default)
        {
            var options = _options.CurrentValue;
            var healthUrl = $"{options.ServiceDiscovery.BaseUrl}/api/service-discovery/update-instance-health";

            try
            {
                var json = JsonSerializer.Serialize(healthDto);
                var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");

                var response = await _httpClient.PostAsync(healthUrl, content, cancellationToken);
                response.EnsureSuccessStatusCode();

                _logger.LogDebug("健康状态更新成功: {ServiceName}/{InstanceId} -> {HealthStatus}",
                    healthDto.ServiceName, healthDto.InstanceId, healthDto.HealthStatus);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "健康状态更新失败: {ServiceName}/{InstanceId}",
                    healthDto.ServiceName, healthDto.InstanceId);
                throw new InvalidOperationException($"健康状态更新失败: {healthDto.ServiceName}", ex);
            }
        }

        /// <summary>
        /// 检查服务是否存在
        /// </summary>
        public async Task<bool> ServiceExistsAsync(string serviceName, CancellationToken cancellationToken = default)
        {
            var cacheKey = $"service_exists:{serviceName}";

            if (_cache.TryGetValue(cacheKey, out bool? cachedExists) && cachedExists.HasValue)
            {
                return cachedExists.Value;
            }

            var options = _options.CurrentValue;
            var existsUrl = $"{options.ServiceDiscovery.BaseUrl}/api/service-discovery/exists/{serviceName}";

            try
            {
                var response = await _httpClient.GetAsync(existsUrl, cancellationToken);
                var exists = response.IsSuccessStatusCode;

                // 缓存结果（较短的缓存时间）
                var cacheOptions = new MemoryCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(30)
                };
                _cache.Set(cacheKey, exists, cacheOptions);

                _logger.LogDebug("检查服务存在性: {ServiceName} -> {Exists}", serviceName, exists);
                return exists;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "检查服务存在性失败: {ServiceName}", serviceName);
                return false;
            }
        }

        /// <summary>
        /// 获取服务统计信息
        /// </summary>
        public async Task<ServiceStatisticsDto?> GetServiceStatisticsAsync(string serviceName, CancellationToken cancellationToken = default)
        {
            var options = _options.CurrentValue;
            var statsUrl = $"{options.ServiceDiscovery.BaseUrl}/api/service-discovery/statistics/{serviceName}";

            try
            {
                var response = await _httpClient.GetAsync(statsUrl, cancellationToken);
                response.EnsureSuccessStatusCode();

                var json = await response.Content.ReadAsStringAsync(cancellationToken);
                var statistics = JsonSerializer.Deserialize<ServiceStatisticsDto>(json, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                });

                _logger.LogDebug("获取服务统计信息: {ServiceName} -> {TotalInstances}个实例",
                    serviceName, statistics?.TotalInstances ?? 0);

                return statistics;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "获取服务统计信息失败: {ServiceName}", serviceName);
                return null;
            }
        }

        #region Private Methods

        /// <summary>
        /// 根据负载均衡策略选择实例
        /// </summary>
        private ServiceInstanceDto SelectInstanceByLoadBalancing(string serviceName, List<ServiceInstanceDto> instances)
        {
            var options = _options.CurrentValue;
            var strategy = options.LoadBalancing.Strategy;

            return strategy.ToLowerInvariant() switch
            {
                "roundrobin" => SelectRoundRobinInstance(serviceName, instances),
                "random" => SelectRandomInstance(instances),
                "weightedroundrobin" => SelectWeightedRoundRobinInstance(instances),
                "leastconnections" => SelectLeastConnectionsInstance(instances),
                _ => SelectRoundRobinInstance(serviceName, instances) // 默认轮询
            };
        }

        private static ServiceInstanceDto SelectRoundRobinInstance(string serviceName, List<ServiceInstanceDto> instances)
        {
            // 简化的轮询实现，实际应该维护轮询状态
            var hash = serviceName.GetHashCode();
            var index = Math.Abs(hash) % instances.Count;
            return instances[index];
        }

        private static ServiceInstanceDto SelectRandomInstance(List<ServiceInstanceDto> instances)
        {
            var random = new Random();
            return instances[random.Next(instances.Count)];
        }

        private static ServiceInstanceDto SelectWeightedRoundRobinInstance(List<ServiceInstanceDto> instances)
        {
            var totalWeight = instances.Sum(x => x.Weight);
            if (totalWeight == 0) return SelectRoundRobinInstance("default", instances);

            var random = new Random();
            var targetWeight = random.Next(totalWeight);

            var currentWeight = 0;
            foreach (var instance in instances.OrderBy(x => x.Weight))
            {
                currentWeight += instance.Weight;
                if (currentWeight >= targetWeight)
                    return instance;
            }

            return instances.Last();
        }

        private static ServiceInstanceDto SelectLeastConnectionsInstance(List<ServiceInstanceDto> instances)
        {
            // 简化实现：选择权重最高的实例
            // 实际应该维护连接数统计
            return instances.OrderByDescending(x => x.Weight).First();
        }

        #endregion
    }
}